#include <vector>
#include <cassert>
#include <stdexcept>

#define IMPLEMENT_INDEXABLE_CLASS(SomeClass) \
	static int& GetClassIndexStatic() \
	{ \
		static int index = -1; \
		return index; \
	} \
	virtual int& GetClassIndex() \
	{ \
		assert(typedid(*this) == typeid(SomeClass)); \
		return GetClassIndexStatic(); \
	}

template 
<
	class BaseLhs,
	class BaseRhs = BaseLhs,
	typename ResultType = void,
	typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)
>
class BasicFastDispatcher
{
	typedef std::vector<CallbackType> Row;
	typedef std::vector<Row> Matrix;
	Matrix callbacks_;
	int nextIndex_;
public:
	BasicFastDispatcher() : nextIndex_(0) {}
	template<class SomeLhs, class SomeRhs> void Add(CallbackType pFun);
	ResultType Go(BaseLhs& lhs,BaseRhs& rhs);
};

template<class BaseLhs,class BaseRhs,typename ResultType,typename CallbackType>
template<class SomeLhs, class SomeRhs>
void BasicFastDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>::Add(CallbackType pFun)
{
	int& idxLhs = SomeLhs::GetClassIndexStatic();
	if (idxLhs < 0) {
		callbacks_.resize(++nextIndex_);
		idxLhs = callbacks_.size() - 1;
	}
	else if (callbacks_.size() <= idxLhs) {
		callbacks_.resize(idxLhs + 1);
	}
	Row& thisRow = callbacks_[idxLhs];
	
	int& idxRhs = SomeRhs::GetClassIndexStatic();
	if (idxRhs < 0) {
		thisRow.resize(++nextIndex_);
		idxRhs = thisRow.size() - 1;
	}
	else if (thisRow.size() <= idxRhs) {
		thisRow.resize(idxRhs + 1);
	}
	thisRow[idxRhs] = pFun;
}

template<class BaseLhs,class BaseRhs,typename ResultType,typename CallbackType>
ResultType BasicFastDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>::Go(BaseLhs& lhs,BaseRhs& rhs)
{
	int& idxLhs = lhs.GetClassIndex();
	int& idxRhs = rhs.GetClassIndex();
	if (idxLhs < 0 || idxRhs < 0 ||
		idxLhs >= callbacks_.size() || idxRhs >= callbacks_[idxLhs].size() ||
		callbacks_[idxLhs][idxRhs] == 0 ) {
			throw std::runtime_error("wrong dispatcher");
	}
	return callbacks_[idxLhs][idxRhs](lhs,rhs);
}